#!/usr/bin/env python3
# -*- coding: utf-8 -*-
def power(x, n):
    s = 1
    while n > 0:
        n = n - 1
        s = s * x
    return s


print(power(2, 2))

'''
在Python函数中，默认参数不能放在必选参数前面，主要有以下原因：

一、从函数调用的语义逻辑角度

明确参数传递顺序
当定义函数时，必选参数要求调用者必须明确提供值。如果默认参数放在必选参数之前，会导致调用者在传递参数时产生混淆。例如：
def 02_func(a = 1, b):
    pass
当调用func(2)时，Python无法确定2是赋给a（默认参数）还是b（必选参数）。因为按照正常的逻辑顺序，先出现的应该是必选参数，后出现的才是可选的（有默认值的参数）。
符合函数使用的预期习惯
在大多数编程场景下，人们习惯先提供必要的信息，然后再根据需要提供可选的补充信息。例如，在定义一个函数来创建一个人的对象，可能必选参数是姓名，而默认参数可以是年龄（假设默认年龄为18岁）。
def create_person(name, age = 18):
    pass
这样的顺序符合人们对创建对象时先确定关键属性（姓名），再考虑非关键属性（年龄）的思维习惯。
二、从Python的解析机制角度

参数解析顺序的限制
Python在解析函数调用时是按照参数定义的顺序依次匹配值的。如果默认参数在前，必选参数在后，在解析函数调用时，对于那些只提供部分参数的情况，Python无法准确地将提供的值分配到正确的参数位置上。
假设允许默认参数在必选参数之前，当调用函数时提供的参数个数少于定义的参数个数时，Python将难以确定哪些参数应该使用默认值，哪些参数需要从调用者提供的值中获取。
所以，为了保证函数调用的清晰性、准确性以及符合Python的解析机制，规定默认参数不能放在必选参数前面。


'''


def power2(x, n=2):
    s = 1
    while n > 0:
        n = n - 1
        s = s * x
    return s


print(power2(2))
print(power2(2, 3))


def enroll(name, gender, age=6, city='Beijing'):
    print('name:', name)
    print('gender:', gender)
    print('age:', age)
    print('city:', city)


enroll('Bob', 'M', 7)
'''
有多个默认参数时，调用的时候，既可以按顺序提供默认参数，比如调用enroll('Bob', 'M', 7)，意思是，除了name，gender这两个参数外，最后1个参数应用在参数age上，city参数由于没有提供，仍然使用默认值。
也可以不按顺序提供部分默认参数。当不按顺序提供部分默认参数时，需要把参数名写上。比如调用enroll('Adam', 'M', city='Tianjin')，意思是，city参数用传进去的值，其他默认参数继续使用默认值。
'''
enroll('Adam', 'M', city='Tianjin')


# 不可变参数
def add_end(L=None):
    if L is None:
        L = []
    L.append('END')
    return L

# 可变参数
def calc(*numbers):
    sum = 0
    for n in numbers:
        sum = sum + n * n
    return sum
'''
在Python中，定义可变参数和定义一个list或tuple参数相比，仅仅在参数前面加了一个*号。在函数内部，参数numbers接收到的是一个tuple，因此，函数代码完全不变。但是，调用该函数时，可以传入任意个参数，包括0个参数：
'''
print(calc(1, 2, 3))
'''
如果已经有一个list或者tuple，要调用一个可变参数怎么办？可以这样做：
'''
nums = [1, 2, 3]
print(calc(*nums))